#pragma once

#include <SockOpt.h>
#include <AsyncLogger.h>
#include <TcpConnection.h>
#include <EventbasePool.h>
#include <InetAddress.h>
#include <event2/listener.h>
#include <event2/event.h>
#include <event2/thread.h>
#include <unordered_map>
#include <memory>
#include <functional>

struct ConnectTask {
    Socket* socket_;
    event_base* base_;
    TcpServer* server_;
};

class TcpServer
{
public:
    TcpServer(const std::string &ip, int port, int backlog = 30);

    ~TcpServer();

    bool Start(int eventbaseSize = 8);

    std::string localIp() { return listenAddr_.ip(); }

    void closeConnectionCallback(const std::shared_ptr<TcpConnection>& conn);
    void onMessageCallback(const std::shared_ptr<TcpConnection>& conn, Buffer& inBuffer);
    void onWriteCompleteCallback(const std::shared_ptr<TcpConnection>& conn);

	void setMessageCallback(MessageCallback cb) { messageCallback_ = cb; };
	void setWriteCompleteCallback(WriteCompleteCallback cb) { writeCompleteCallback_ = cb; };
    void setConnectionCallback(ConnectionCallback cb) { connectionCallback_ = cb; };
    void setCloseCallback(CloseConnectionCallback cb) { closeCallback_ = cb; }

    void Stop();
private:
    void listenCallback(evconnlistener *listener, socket_t sockfd, sockaddr *addr, int socklen, void *arg);
    void connectionEstanblish(ev_socklen_t sockfd, int event, void* arg);
private:
    std::mutex connMapLock_;
    event_base* base_;
    bool started_;
    InetAddress listenAddr_;
    std::unordered_map<std::string, std::shared_ptr<TcpConnection>> connMap_;
    std::unique_ptr<evconnlistener, std::function<void(evconnlistener *)>> listener_;
    std::unique_ptr<EventbasePool> eventbasePool_;

    /*
    note: TCP服务器的回调函数
        回调函数由外界封装时设置，目的是提高灵活性，对不同的服务可以传入不同的处理方法，比如http、ftp服务，
        用户可以自己在外面封装httpserver、ftpserver等不同的服务。
        对于不同的服务read到的数据包，可以传入不同的处理方法，比如http服务可以传入http解析函数，
        echo服务可以传入echo处理函数，这样可以提高代码的复用性，降低代码的耦合性。
    */
    WriteCompleteCallback writeCompleteCallback_;
    MessageCallback messageCallback_;
    ConnectionCallback connectionCallback_;
    CloseConnectionCallback closeCallback_;
};